#pragma once

// 声明一个静态方法，我可以传入回调函数，当状态变化时触发回调函数
#include <atomic>
#include <cstdint>
#include <functional>

class SR501 {
  private:
    SR501();
    static std::atomic<bool> is_running;
  public:
    static void listen_state(std::function<void(bool state)> fn);
    static void stop_listen_state();
};

const uint8_t success_text[][60] = {
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFE, 0xE0, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x38, 0x0F, 0x00,
     0x01, 0x0E, 0x38, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x02, 0x01,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x02, 0x02, 0x00}, /*"人",0*/
    {0x00, 0x00, 0x00, 0xFC, 0x44, 0x44, 0xFC, 0x04, 0x00, 0x80, 0x60, 0x18, 0x0E, 0x08, 0x10,
     0x60, 0xC0, 0x80, 0x80, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x04, 0x04, 0xFF, 0x01, 0x01, 0x30,
     0xE1, 0x05, 0x79, 0x01, 0x81, 0x71, 0x1D, 0x05, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x02,
     0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03, 0x02, 0x00}, /*"脸",1*/
    {0x00, 0x00, 0x20, 0x20, 0xFE, 0x20, 0x20, 0x20, 0xA0, 0x40, 0x30, 0x1C, 0x06, 0x18, 0x20,
     0x40, 0xC0, 0x80, 0x80, 0x00, 0x00, 0x20, 0x18, 0x07, 0xFF, 0x01, 0x03, 0x03, 0x18, 0xE0,
     0x01, 0x0D, 0x71, 0x01, 0xC1, 0x3D, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
     0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 0x02, 0x00, 0x00}, /*"检",2*/
    {0x00, 0x00, 0xC2, 0x04, 0x0C, 0xC0, 0xFC, 0x04, 0x04, 0xE4, 0x04, 0xFC, 0x00, 0x00, 0xF0,
     0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x20, 0x20, 0xF0, 0x0E, 0x01, 0x3F, 0x80, 0x70, 0x0F,
     0x80, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x04,
     0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x02, 0x06, 0x03, 0x00, 0x00}, /*"测",3*/
    {0x00, 0x00, 0x00, 0xE0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0xFC, 0x20, 0x22, 0x24,
     0x38, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x02, 0x02, 0x82, 0x82, 0xFE, 0x00,
     0x00, 0x07, 0xF8, 0x60, 0xB8, 0x0E, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00,
     0x00, 0x00, 0x01, 0x04, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x02, 0x07, 0x00}, /*"成",4*/
    {0x00, 0x00, 0x10, 0x10, 0x10, 0xE0, 0x10, 0x10, 0x10, 0x10, 0x40, 0x40, 0x82, 0x7E, 0x40,
     0x40, 0x40, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x40, 0x40, 0x3F, 0x20, 0x20, 0x20, 0x10,
     0xC0, 0x70, 0x1F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x04, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x06, 0x03, 0x00, 0x00, 0x00}, /*"功",5*/
};

const uint8_t fail_text[][60] = {
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFE, 0xE0, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x38, 0x0F, 0x00,
     0x01, 0x0E, 0x38, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x02, 0x01,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x02, 0x02, 0x00}, /*"人",0*/
    {0x00, 0x00, 0x00, 0xFC, 0x44, 0x44, 0xFC, 0x04, 0x00, 0x80, 0x60, 0x18, 0x0E, 0x08, 0x10,
     0x60, 0xC0, 0x80, 0x80, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x04, 0x04, 0xFF, 0x01, 0x01, 0x30,
     0xE1, 0x05, 0x79, 0x01, 0x81, 0x71, 0x1D, 0x05, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x02,
     0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03, 0x02, 0x00}, /*"脸",1*/
    {0x00, 0x00, 0x20, 0x20, 0xFE, 0x20, 0x20, 0x20, 0xA0, 0x40, 0x30, 0x1C, 0x06, 0x18, 0x20,
     0x40, 0xC0, 0x80, 0x80, 0x00, 0x00, 0x20, 0x18, 0x07, 0xFF, 0x01, 0x03, 0x03, 0x18, 0xE0,
     0x01, 0x0D, 0x71, 0x01, 0xC1, 0x3D, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
     0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 0x02, 0x00, 0x00}, /*"检",2*/
    {0x00, 0x00, 0xC2, 0x04, 0x0C, 0xC0, 0xFC, 0x04, 0x04, 0xE4, 0x04, 0xFC, 0x00, 0x00, 0xF0,
     0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x20, 0x20, 0xF0, 0x0E, 0x01, 0x3F, 0x80, 0x70, 0x0F,
     0x80, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x04,
     0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x02, 0x06, 0x03, 0x00, 0x00}, /*"测",3*/
    {0x00, 0x00, 0x00, 0x80, 0x60, 0x38, 0x20, 0x20, 0x20, 0xFE, 0x7C, 0x20, 0x20, 0x20, 0x20,
     0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x02, 0x82, 0xC2, 0x3A, 0x0F,
     0x04, 0x1A, 0x22, 0xC2, 0x82, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02,
     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02, 0x02, 0x00}, /*"失",4*/
    {0x00, 0x00, 0xFC, 0x04, 0x04, 0xE4, 0x04, 0xFC, 0x04, 0x00, 0xC0, 0xF8, 0x26, 0x20, 0x20,
     0xC0, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x78, 0x07, 0x20, 0x5F, 0xC0, 0x01,
     0x00, 0x03, 0x9C, 0x60, 0xD8, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x05, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x02, 0x02, 0x00}, /*"败",5*/
};

class OLED {

#define SSD1306_I2C_BUS 5
#define SSD1306_I2C_ADDR 0x3c

#define SSD1306_WIDTH 128
#define SSD1306_HEIGHT 32

#define SSD1306_COMM_CONTROL_BYTE 0x00
#define SSD1306_DATA_CONTROL_BYTE 0x40

#define SSD1306_COMM_DISPLAY_OFF 0xae
#define SSD1306_COMM_DISPLAY_ON 0xaf
#define SSD1306_COMM_HORIZ_NORM 0xa0
#define SSD1306_COMM_HORIZ_FLIP 0xa1
#define SSD1306_COMM_RESUME_RAM 0xa4
#define SSD1306_COMM_IGNORE_RAM 0xa5
#define SSD1306_COMM_DISP_NORM 0xa6
#define SSD1306_COMM_DISP_INVERSE 0xa7
#define SSD1306_COMM_MULTIPLEX 0xa8
#define SSD1306_COMM_VERT_OFFSET 0xd3
#define SSD1306_COMM_CLK_SET 0xd5
#define SSD1306_COMM_PRECHARGE 0xd9
#define SSD1306_COMM_COM_PIN 0xda
#define SSD1306_COMM_DESELECT_LV 0xdb
#define SSD1306_COMM_CONTRAST 0x81
#define SSD1306_COMM_DISABLE_SCROLL 0x2e
#define SSD1306_COMM_ENABLE_SCROLL 0x2f
#define SSD1306_COMM_PAGE_NUMBER 0xb0
#define SSD1306_COMM_LOW_COLUMN 0x00
#define SSD1306_COMM_HIGH_COLUMN 0x10

#define SSD1306_COMM_START_LINE 0x40

#define SSD1306_COMM_CHARGE_PUMP 0x8d

#define SSD1306_COMM_SCAN_NORM 0xc0
#define SSD1306_COMM_SCAN_REVS 0xc8

#define SSD1306_COMM_MEMORY_MODE 0x20
#define SSD1306_COMM_SET_COL_ADDR 0x21
#define SSD1306_COMM_SET_PAGE_ADDR 0x22

#define SSD1306_HORI_MODE 0x00
#define SSD1306_VERT_MODE 0x01
#define SSD1306_PAGE_MODE 0x02

#define SSD1306_128_32_LINES 32

#define SSD1306_128_64_COLUMNS 128
#define SSD1306_128_32_COLUMNS 128
#define SSD1306_64_48_COLUMNS 64

  private:
    int file_i2c;
    uint8_t data_buf_[1024];
    uint8_t max_lines_   = SSD1306_HEIGHT;
    uint8_t max_columns_ = SSD1306_WIDTH;
    uint8_t global_x_    = 0;
    uint8_t global_y_    = 0;

    bool is_first_show_{true};

    bool pre_status_{false};

    OLED();

    void _i2c_init();
    void _i2c_write(uint8_t * ptr, int16_t len);
    void _i2c_read(uint8_t * ptr, int16_t len);

    void set_XY(uint8_t x, uint8_t y);

    void clear_line(uint8_t y);
    void clean_screen();

  public:
    static void show(bool is_check);
};